package com.repair.gateway.config;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.util.SaResult;
import com.repair.api.user.constant.UserPermissionEnum;
import com.repair.api.worker.constant.WorkerPermissionEnum;
import com.repair.base.exception.BizErrorCode;
import com.repair.base.exception.BizException;
import com.repair.gateway.utils.StpKit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author chunyu
 * @since 2024/9/26,20:15
 * 这个是sa-token 官网提供的方法
 */
@Slf4j
@Configuration
public class SaTokenConfigure {

    // 注册 Sa-Token全局过滤器
    @Bean
    public SaReactorFilter getSaReactorFilter() {
        return new SaReactorFilter()
                // 拦截地址
                .addInclude("/**")    /* 拦截全部path */
                // 开放地址
                .addExclude("/favicon.ico", "/auth/**", "/worker/upload")
                // 鉴权方法：每次访问进入
                .setAuth(obj -> {
                    // 登录校验 -- 拦截所有路由，并排除/user/doLogin 用于开放登录 后续还要继续加
                    /*SaRouter.match("/**")
                            .notMatch("/auth/**")
                            .notMatch("/pay.html")
                            .check(r -> StpKit.USER.checkLogin());
                    SaRouter.match("/**")
                            .notMatch("/auth/workerReg")
                            .notMatch("/auth/sendWorkerCaptcha")
                            .notMatch("/auth/workerReg")
                            .check(r -> StpKit.WORKER.checkLogin());*/

                    // 权限认证 -- 不同模块, 校验不同权限  一个checkPermission  多个checkPermissionOr
                    SaRouter.match("/user/**", r ->
                            StpKit.USER.checkPermissionOr(UserPermissionEnum.LOGIN.name(), UserPermissionEnum.AUTH.name(), UserPermissionEnum.BLOCK.name())
                    );
                    // 师傅模块在这改
                    SaRouter.match("/worker/**", r ->
                            StpKit.WORKER.checkPermissionOr(WorkerPermissionEnum.LOGIN.name(), WorkerPermissionEnum.AUTH.name(), WorkerPermissionEnum.BLOCK.name())
                    );

                    SaRouter.match("/order/worker/getOrders", r -> {
                        StpKit.WORKER.checkPermissionOr(WorkerPermissionEnum.LOGIN.name(), WorkerPermissionEnum.AUTH.name(), WorkerPermissionEnum.BLOCK.name());
                    });
                    SaRouter.match("/order/worker/getGrabPools", r -> {
                        if (StpKit.WORKER.hasPermission(WorkerPermissionEnum.BLOCK.name())) {
                            throw new BizException(BizErrorCode.USER_BLOCKED);
                        }
                        StpKit.WORKER.checkPermissionOr(WorkerPermissionEnum.AUTH.name());
                    });
                    SaRouter.match("/order/worker/getDispatchPool", r -> {
                        if (StpKit.WORKER.hasPermission(WorkerPermissionEnum.BLOCK.name())) {
                            throw new BizException(BizErrorCode.USER_BLOCKED);
                        }
                        StpKit.WORKER.checkPermissionOr(WorkerPermissionEnum.AUTH.name());
                    });
                    SaRouter.match("/order/worker/grabOrder", r -> {
                        if (StpKit.WORKER.hasPermission(WorkerPermissionEnum.BLOCK.name())) {
                            throw new BizException(BizErrorCode.USER_BLOCKED);
                        }
                        StpKit.WORKER.checkPermissionOr(WorkerPermissionEnum.AUTH.name());
                    });
                    SaRouter.match("/order/worker/submitWorkBefore", r -> StpKit.WORKER.checkPermissionOr(WorkerPermissionEnum.AUTH.name()));
                    SaRouter.match("/order/worker/submitWorkAfter", r -> StpKit.WORKER.checkPermissionOr(WorkerPermissionEnum.AUTH.name()));
                    SaRouter.match("/order/worker/acceptOrder", r -> StpKit.WORKER.checkPermissionOr(WorkerPermissionEnum.AUTH.name()));
                    SaRouter.match("/order/worker/rejectOrder", r -> StpKit.WORKER.checkPermissionOr(WorkerPermissionEnum.AUTH.name()));


                    // 用户预约下单
                    SaRouter.match("/order/createOrder", r -> {
                        if (StpKit.USER.hasPermission(UserPermissionEnum.BLOCK.name())) {
                            throw new BizException(BizErrorCode.USER_BLOCKED);
                        }
                        // 检查权限
                        StpKit.USER.checkPermissionOr(UserPermissionEnum.LOGIN.name(), UserPermissionEnum.AUTH.name());
                    });

                    //SaRouter.match("/order/worker/**", r -> StpKit.WORKER.checkPermissionOr(WorkerPermissionEnum.AUTH.name()));
                    //SaRouter.match("/orders/**", r -> StpKit.USER.checkPermissionOr(UserPermissionEnum.LOGIN.name(), UserPermissionEnum.AUTH.name(), UserPermissionEnum.BLOCK.name()));
                    //SaRouter.match("/orders/**", r -> StpUtil.checkPermissionOr(UserPermissionEnum.LOGIN.name(), UserPermissionEnum.AUTH.name(), UserPermissionEnum.BLOCK.name()));

                    // 更多匹配 ...  */
                })
                // 异常处理方法：每次setAuth函数出现异常时进入
                //.setError(this::getSaResult);
                .setError(this::getSaResult)

                // 前置函数：在每次认证函数之前执行
                .setBeforeAuth(obj -> {
                    SaHolder.getResponse()

                            // ---------- 设置跨域响应头 ----------
                            // 允许指定域访问跨域资源
                            .setHeader("Access-Control-Allow-Origin", "*")
                            // 允许所有请求方式
                            .setHeader("Access-Control-Allow-Methods", "*")
                            // 允许的header参数
                            .setHeader("Access-Control-Allow-Headers", "*")
                            // 有效时间
                            .setHeader("Access-Control-Max-Age", "3600");
                    // 如果是预检请求，则立即返回到前端
                    SaRouter.match(SaHttpMethod.OPTIONS)
                            .free(r -> log.info("options不处理"))
                            .back();
                });
    }

    private SaResult getSaResult(Throwable throwable) {


        // 这里只能每种情况试一下抛什么异常
        if (throwable instanceof NotLoginException) {
            log.error("请先登录");
            return SaResult.error("请先登录");
        } else if (throwable instanceof NotPermissionException) {
            NotPermissionException ex = (NotPermissionException) throwable;
            if (UserPermissionEnum.AUTH.name().equals(ex.getPermission())) {
                log.error("您没有实名");
                return SaResult.error("请先实名");
            } else if (UserPermissionEnum.BLOCK.name().equals(ex.getPermission())) {
                log.error("您的账号被封禁");
                return SaResult.error("您的账号被封禁");
            } else if (UserPermissionEnum.LOGIN.name().equals(ex.getPermission())) {
                log.error("您没有登录");
                return SaResult.error("请先登录");
            }
        } else if (throwable instanceof BizException) {
            BizException ex = (BizException) throwable;
            return SaResult.error(ex.getErrorCode().getMessage());
        }
        throwable.printStackTrace();
        return SaResult.error("权限异常");
    }

}